package api

import (
	"context"
	"net"

	"dev.ixmxm.top/rms/boot"
	"dev.ixmxm.top/rms/codes"
	"dev.ixmxm.top/rms/managers/chargemanager"
	"dev.ixmxm.top/rms/managers/robotmanager"
	"dev.ixmxm.top/rms/model"
	"dev.ixmxm.top/rms/proto"
	"dev.ixmxm.top/rms/utils/log"
)

// @Summary 充电桩配置数据添加
// @Description
// @Accept application/json
// @Produce application/json
// @Param body body saveChargerParams true "充电桩配置"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 充电桩
// @Router /charger/add_charger [post]
func (hg *HttpGateway) AddCharger(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*saveChargerParams)
	//验证数据是否正常
	if p.ChargeID < 1 {
		return nil, codes.ErrInvalidParams.WithDetails("输入的编号有误，必须为大于0的数字")
	}
	address := net.ParseIP(p.ChargerIp)
	if address == nil {
		return nil, codes.ErrInvalidParams.WithDetails("输入的IP地址不合法")
	}
	if !hg.dispatcher.TRM().MapNameExists(p.MapName) {
		return nil, codes.ErrMapNotFound
	}
	//验证地图是否存在
	mapCharger, err := hg.dispatcher.TRM().GetMapByNameFromDB(ctx, p.MapName)
	if err != nil {
		return nil, err
	}
	if mapCharger == nil {
		return nil, codes.ErrMapNotFound
	}
	site, find := mapCharger.MapData.NodesMap[p.SiteId]
	if !find {
		return nil, codes.ErrMapNodeNotFound
	}
	if site.Type != model.NodeCharge {
		return nil, codes.ErrMapNodeNotFound
	}
	//验证重复
	chargers, err := hg.dispatcher.CM().GetAllChargerPointsFromDB(ctx)
	if err != nil {
		log.ErrorfWithContext(ctx, "get all charger points error:%s", err.UnWrapError())
		return nil, err
	}
	for _, charger := range chargers {
		if p.ChargeID == charger.Id {
			return nil, codes.ErrInvalidParams.WithDetails("已存在该ID")
		}
		if p.ChargerIp == charger.Ip && p.ChargePort == charger.Port {
			return nil, codes.ErrInvalidParams.WithDetails("已存在该IP和端口号，不可同时重复")
		}
		if p.MapName == charger.MapName && p.SiteId == charger.SiteId {
			return nil, codes.ErrInvalidParams.WithDetails("已存在该点位的充电桩，不可重复")
		}
	}

	return nil, hg.dispatcher.CM().AddChargePointToDB(ctx, p.ChargeID, p.MapName, p.SiteId, p.ChargerIp, p.ChargePort, p.BanAgvList)
}

// @Summary 充电桩配置数据保存
// @Description
// @Accept application/json
// @Produce application/json
// @Param body body saveChargerParams true "充电桩配置"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 充电桩
// @Router /charger/save_charger [post]
func (hg *HttpGateway) SaveCharger(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*saveChargerParams)
	//验证数据是否正常
	if p.ChargeID < 1 {
		return nil, codes.ErrInvalidParams.WithDetails("输入的编号有误，必须为大于0的数字")
	}
	address := net.ParseIP(p.ChargerIp)
	if address == nil {
		return nil, codes.ErrInvalidParams.WithDetails("输入的IP地址不合法")
	}
	if !hg.dispatcher.TRM().MapNameExists(p.MapName) {
		return nil, codes.ErrMapNotFound
	}
	//验证地图是否存在
	mapCharger, err := hg.dispatcher.TRM().GetMapByNameFromDB(ctx, p.MapName)
	if err != nil {
		return nil, err
	}
	if mapCharger == nil {
		return nil, codes.ErrMapNotFound
	}
	site, find := mapCharger.MapData.NodesMap[p.SiteId]
	if !find {
		return nil, codes.ErrMapNodeNotFound
	}
	if site.Type != model.NodeCharge {
		return nil, codes.ErrMapNodeNotFound
	}
	//验证重复
	chargers, err := hg.dispatcher.CM().GetAllChargerPointsFromDB(ctx)
	if err != nil {
		log.ErrorfWithContext(ctx, "get all charger points error:%s", err.UnWrapError())
		return nil, err
	}
	isAny := false
	for _, charger := range chargers {
		if p.ChargeID == charger.Id {
			isAny = true
		}
		if p.ChargeID != charger.Id && p.ChargerIp == charger.Ip && p.ChargePort == charger.Port {
			return nil, codes.ErrInvalidParams.WithDetails("已存在该IP和端口号，不可同时重复")
		}
		if p.ChargeID != charger.Id && p.MapName == charger.MapName && p.SiteId == charger.SiteId {
			return nil, codes.ErrInvalidParams.WithDetails("已存在该点位的充电桩，不可重复")
		}
	}
	if !isAny {
		return nil, codes.ErrInvalidParams.WithDetails("数据库不存在该充电桩ID")
	}

	return nil, hg.dispatcher.CM().AddChargePointToDB(ctx, p.ChargeID, p.MapName, p.SiteId, p.ChargerIp, p.ChargePort, p.BanAgvList)
}

// @Summary 删除充电桩
// @Description
// @Accept application/json
// @Produce application/json
// @Param charge_id query uint8 true "充电桩配置"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 充电桩
// @Router /charger/delete_charger [delete]
func (hg *HttpGateway) DeleteCharger(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*deleteChargerParams)
	return nil, hg.dispatcher.CM().DeleteChargePointFromDB(ctx, p.ChargeID)
}

// @Summary 批量删除充电桩
// @Description
// @Accept application/json
// @Produce application/json
// @Param charge_ids query []uint8 true "充电桩配置"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 充电桩
// @Router /charger/delete_chargers [delete]
func (hg *HttpGateway) DeleteChargers(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*deleteChargersParams)
	txctx := boot.Begin(ctx)
	for _, chargeId := range p.ChargeIds {
		err := hg.dispatcher.CM().DeleteChargePointFromDB(txctx, chargeId)
		if err != nil {
			txctx.Rollback()
			return nil, err
		}
	}
	txctx.Commit()
	return nil, nil
}

// @Summary 删除充电桩根据点位信息
// @Description
// @Accept application/json
// @Produce application/json
// @Param map_name query string true "充电桩地图"
// @Param site_id query string true "充电桩点位"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 充电桩
// @Router /charger/delete_charger_by_siteid [delete]
func (hg *HttpGateway) DeleteChargerBySiteid(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*GetChargerParams)
	res, err := hg.dispatcher.CM().GetAllChargerPointsFromDB(ctx)
	if err != nil {
		log.ErrorfWithContext(ctx, "get all charger points error:%s", err.UnWrapError())
		return nil, err
	}
	for _, charger := range res {
		if charger.MapName == p.MapName && charger.SiteId == p.SiteId {
			return nil, hg.dispatcher.CM().DeleteChargePointFromDB(ctx, charger.Id)
		}
	}
	return nil, nil
}

// @Summary 获取所有充电桩配置数据
// @Description
// @Accept application/json
// @Produce application/json
// @Success 0 {object} ResponseExampleList "返回数据格式"
// @Success 1 {object} []model.ChargeSite "data数据：充电桩配置集合"
// @Tags 充电桩
// @Router /charger/get_chargers [get]
func (hg *HttpGateway) GetChargers(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	res, err := hg.dispatcher.CM().GetAllChargerPointsFromDB(ctx)
	if err != nil {
		log.ErrorfWithContext(ctx, "get all charger points error:%s", err.UnWrapError())
		return nil, err
	}
	return res, nil
}

// @Summary 获取充电桩配置数据
// @Description
// @Accept application/json
// @Produce application/json
// @Param map_name query string true "充电桩地图"
// @Param site_id query string true "充电桩点位"
// @Success 0 {object} ResponseExampleStruct "返回数据格式"
// @Success 1 {object} model.ChargeSite "data数据：充电桩配置"
// @Tags 充电桩
// @Router /charger/get_charger [get]
func (hg *HttpGateway) GetCharger(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*GetChargerParams)
	res, err := hg.dispatcher.CM().GetAllChargerPointsFromDB(ctx)
	if err != nil {
		log.ErrorfWithContext(ctx, "get all charger points error:%s", err.UnWrapError())
		return nil, err
	}
	for _, charger := range res {
		if charger.MapName == p.MapName && charger.SiteId == p.SiteId {
			return charger, nil
		}
	}
	return nil, codes.ErrChargerNotFound
}

// @Summary 手动释放充电桩
// @Description
// @Accept application/json
// @Produce application/json
// @Param body body releaseChargerParams true "充电桩"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 充电桩
// @Router /charger/release_charger [post]
func (hg *HttpGateway) ReleaseCharger(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*releaseChargerParams)
	//获取充电桩信息
	charger := hg.dispatcher.CM().GetChargersFromCache(ctx, p.ChargeId)
	if charger == nil {
		log.Errorf("手动释放充电桩,未找到充电桩  chargerId:%d", p.ChargeId)
		return nil, codes.ErrChargeNodeExists
	}
	if charger.GetInfo().AgvID == "" {
		return nil, nil
	}
	//获取充电任务
	ctxTx := boot.Begin(ctx)

	task, err := hg.dispatcher.TM().GetRobotRunningTaskFromDB(ctxTx, charger.GetInfo().AgvID)
	if err != nil {
		log.Errorf("手动释放充电桩,查询小车执行中的任务出错  chargerId:%d", p.ChargeId)
		err = hg.dispatcher.CM().FreeCharger(ctxTx, charger.GetInfo().MapName, charger.GetInfo().SiteId, p.ChargeId)
		if err != nil {
			ctxTx.Rollback()
			return nil, err
		}
		ctxTx.Commit()
		return nil, nil
	}
	//是充电任务，取消充电任务
	if task != nil && task.Type == model.TaskTypeCharge {
		caller, _ := hg.dispatcher.GetCaller(task.AgvId)
		if caller == nil {
			ctxTx.Rollback()
			return nil, codes.ErrRobotOperate.WithDetails("没有找到小车连接")
		}
		newTaskState := model.TaskStatusCanceling
		robot := robotmanager.GetFromCache(task.AgvId)
		if robot.StatusIsExists() && robot.Status.Online {
			if robot.Status.Status == model.RobotStatusCharging {
				log.Infof("小车(%s)下发断电任务...", robot.Account.AgvId)
				err = hg.dispatcher.SendDischargeTask(ctx, robot.Account.AgvId)
				if err != nil {
					log.Errorf("send finish to robot:%s charger error:%s", robot.Account.AgvId, err.UnWrapError())
					return nil, err
				}
			} else if robot.Status.Status != model.RobotStatusIdle && robot.Status.Status != model.RobotStatusStandby {
				//获取子任务
				runSubtask, err := hg.dispatcher.TM().GetRunningSubtaskFromDB(ctxTx, task.AgvId)
				if err != nil {
					ctxTx.Rollback()
					return nil, err
				}
				//机器人任务操作
				errOperate := caller.OperateTask(ctxTx, runSubtask.Id, hg.dispatcher.TM(), proto.TaskOperatePb_TaskCancel)
				if errOperate != nil {
					log.ErrorfWithContext(ctxTx, "operate task error:%s", errOperate.UnWrapError())
					ctxTx.Rollback()
					return nil, errOperate
				}
			} else {
				newTaskState = model.TaskStatusCanceled
			}
		} else {
			newTaskState = model.TaskStatusCanceled
		}
		//更新任务状态
		err = hg.dispatcher.TM().UpdateTaskStatusToDB(ctxTx, task.Id, newTaskState)
		if err != nil {
			ctxTx.Rollback()
			return nil, err
		}
		//更新子任务状态
		runSubtask, err := hg.dispatcher.TM().GetRunningSubtaskFromDB(ctxTx, task.AgvId)
		if err != nil {
			ctxTx.Rollback()
			return nil, err
		}
		err = hg.dispatcher.TM().UpdateSubtaskStatusToDB(ctxTx, runSubtask.Id, newTaskState, false)
		if err != nil {
			ctxTx.Rollback()
			return nil, err
		}
		if newTaskState == model.TaskStatusCanceled {
			//清除全局路径(只清除路径，不清除锁)
			if errDeletePath := hg.dispatcher.TRM().DeleteRobotGlobalPaths(ctx, task.AgvId, task.MapName); errDeletePath != nil {
				ctxTx.Rollback()
				return nil, errDeletePath
			}
			//解除任务绑定
			err = hg.dispatcher.TM().DeleteMainTaskByAgvIdToDB(ctxTx, task.AgvId)
			if err != nil {
				ctxTx.Rollback()
				return nil, err
			}
			//删除对应子任务
			err = hg.dispatcher.TM().DeleteSubtasksToDB(ctxTx, task.Id)
			if err != nil {
				ctxTx.Rollback()
				log.Errorf("手动释放充电桩，数据库删除子任务失败  taskid:%d", task.Id)
				return nil, err
			}
		}
	}
	err = hg.dispatcher.CM().FreeCharger(ctxTx, charger.GetInfo().MapName, charger.GetInfo().SiteId, p.ChargeId)
	if err != nil {
		ctxTx.Rollback()
		return nil, err
	}
	ctxTx.Commit()
	return nil, nil
}

// @Summary 获取所有充电桩状态信息
// @Description
// @Accept application/json
// @Produce application/json
// @Success 0 {object} ResponseExampleList "返回数据格式"
// @Success 1 {object} []model.ChargeStatus "data数据：充电桩集合"
// @Tags 充电桩
// @Router /charger/get_charger_statuses [get]
func (hg *HttpGateway) GetChargerStatuses(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	chargers := hg.dispatcher.CM().GetAllChargersFromCache(context.TODO())
	chargerStatuses := make([]model.ChargeStatus, 0)
	for _, charger := range chargers {
		item := model.ChargeStatus{}
		info := charger.GetInfo()
		item.MapName = info.MapName
		item.SiteId = info.SiteId
		item.Id = info.Id
		item.Online = charger.GetChargerStatus() != chargemanager.ChargerWaitConnect && charger.GetChargerStatus() != chargemanager.ChargerCommunicationOverTime
		item.Charging = charger.GetStatusWord().IsCharging
		item.ErrCode = uint8(charger.GetStatusWord().Code)
		item.AgvID = charger.GetInfo().AgvID
		item.Current = charger.GetStatusWord().Current
		item.IsStretch = charger.GetStatusWord().IsOut
		chargerStatuses = append(chargerStatuses, item)
	}
	return chargerStatuses, nil
}

// @Summary 获取所有断电指令
// @Description
// @Accept application/json
// @Produce application/json
// @Success 0 {object} ResponseExampleList "返回数据格式"
// @Success 1 {object} []model.ChargeStatus "data数据：充电桩集合"
// @Tags 充电桩
// @Router /charger/get_disCharger_cmd [get]
func (hg *HttpGateway) GetDisChargerCmd(ctx context.Context, params interface{}) (interface{}, codes.Code) {

	return hg.dispatcher.GetAllDisChargeList(), nil
}
